const jwt = require('jsonwebtoken');
const User = require('../models/User');
const Message = require('../models/Message');
const friendService = require('../services/friendService');
const { query } = require('../config/mysqlConfig');
const groupMessageService = require('./groupMessageService');

// 存储用户Socket连接的映射
const userSockets = new Map();

// Socket认证中间件
const socketAuth = async (socket, next) => {
  try {
    const token = socket.handshake.auth.token;
    
    if (!token) {
      console.error('Socket认证失败: 没有提供token');
      return next(new Error('身份验证失败'));
    }

    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    const user = await User.findById(decoded.id).select('-password');
    
    if (!user) {
      console.error('Socket认证失败: 用户不存在');
      return next(new Error('用户不存在'));
    }

    // 将用户信息附加到socket
    socket.user = user;
    console.log(`Socket认证成功: ${user.username}`);
    next();
  } catch (error) {
    console.error('Socket认证错误:', error);
    next(new Error('身份验证失败'));
  }
};

// 发送用户状态变更给好友
const emitUserStatus = async (userId, status, io, onlineUsers) => {
  try {
    // 更新用户状态
    await User.findByIdAndUpdate(userId, { status });
    
    // 获取用户好友列表
    const friends = await friendService.getUserFriends(userId);
    
    // 通知所有在线好友
    if (friends && friends.length > 0) {
      friends.forEach(friend => {
        const friendId = friend._id.toString();
        const friendSocketId = onlineUsers[friendId];
        if (friendSocketId) {
          io.to(friendSocketId).emit('userStatusChange', {
            userId,
            status
          });
        }
      });
    }
  } catch (error) {
    console.error('发送用户状态变更错误:', error);
  }
};

// 保存并发送私人消息
const saveAndSendMessage = async (senderId, receiverId, content, type, io) => {
  try {
    // 检查好友关系
    const isFriend = await friendService.checkFriendship(senderId, receiverId);
    if (!isFriend) {
      console.error('消息发送失败: 非好友关系');
      return null;
    }
    
    // 检查是否是短时间内的重复消息(1分钟内相同内容)
    const now = new Date();
    const oneMinuteAgo = new Date(now.getTime() - 60 * 1000);

    const recentDuplicates = await Message.find({
      sender: senderId,
      receiver: receiverId,
      content,
      createdAt: { $gte: oneMinuteAgo }
    });

    // 如果有重复消息，直接返回已存在的消息，避免创建新记录
    if (recentDuplicates.length > 0) {
      console.log('检测到Socket发送的重复消息，使用现有消息');
      const existingMessage = await recentDuplicates[0].populate('sender', 'username avatar');
      await existingMessage.populate('receiver', 'username avatar');
      
      // 获取接收者的Socket
      const receiverSocketId = userSockets.get(receiverId);
      
      // 如果接收者在线，发送消息(标记为可能重复)
      if (receiverSocketId) {
        io.to(receiverSocketId).emit('privateMessage', {
          senderId,
          message: existingMessage,
          possibleDuplicate: true
        });
      }
      
      return existingMessage;
    }
    
    // 创建消息记录
    const message = await Message.create({
      sender: senderId,
      receiver: receiverId,
      content,
      type: type || 'text',
      target_type: 'user'
    });
    
    // 填充发送者和接收者信息
    await message.populate('sender', 'username avatar');
    await message.populate('receiver', 'username avatar');
    
    // 获取接收者的Socket
    const receiverSocketId = userSockets.get(receiverId);
    
    // 如果接收者在线，发送消息
    if (receiverSocketId) {
      io.to(receiverSocketId).emit('privateMessage', {
        senderId,
        message
      });
    }
    
    return message;
  } catch (error) {
    console.error('保存消息失败:', error);
    return null;
  }
};

// 保存并广播群组消息
const saveAndBroadcastGroupMessage = async (senderId, groupId, content, type, io) => {
  try {
    // 检查是否是短时间内的重复消息(1分钟内相同内容)
    const now = new Date();
    const oneMinuteAgo = new Date(now.getTime() - 60 * 1000);

    // 查询最近的群组消息
    const recentMessages = await query(
      `SELECT * FROM group_messages 
       WHERE sender_id = ? AND group_id = ? AND content = ? AND created_at >= ?
       ORDER BY created_at DESC LIMIT 1`,
      [senderId, groupId, content, oneMinuteAgo.toISOString().slice(0, 19).replace('T', ' ')]
    );
    
    let message;
    let possibleDuplicate = false;
    
    if (recentMessages.length > 0) {
      console.log('检测到Socket发送的重复群组消息，使用现有消息');
      message = recentMessages[0];
      possibleDuplicate = true;
    } else {
      // 使用服务层方法保存群组消息
      message = await groupMessageService.sendGroupMessage(
        senderId,
        groupId,
        content,
        type
      );
    }
    
    if (!message) {
      return null;
    }
    
    // 获取群组所有成员
    const members = await query(
      'SELECT user_id FROM group_members WHERE group_id = ?',
      [groupId]
    );
    
    // 获取群组信息
    const groups = await query('SELECT name, group_avatar FROM `groups` WHERE id = ?', [groupId]);
    const groupInfo = groups.length > 0 ? groups[0] : { name: '未知群组', group_avatar: null };
    
    // 广播消息给所有在线成员（除了发送者）
    for (const member of members) {
      const memberId = member.user_id;
      
      // 跳过发送者
      if (memberId === senderId) {
        continue;
      }
      
      const memberSocketId = userSockets.get(memberId);
      if (memberSocketId) {
        io.to(memberSocketId).emit('groupMessage', {
          senderId,
          groupId,
          message,
          groupInfo,
          possibleDuplicate
        });
      }
    }
    
    return message;
  } catch (error) {
    console.error('保存并广播群组消息失败:', error);
    return null;
  }
};

// 处理群组邀请和通知
const notifyGroupInvitation = async (groupId, fromUserId, toUserId, io) => {
  try {
    // 获取群组信息
    const groups = await query('SELECT name, group_avatar FROM `groups` WHERE id = ?', [groupId]);
    if (groups.length === 0) {
      throw new Error('群组不存在');
    }
    
    // 获取邀请人信息
    const inviter = await User.findById(fromUserId).select('username avatar');
    if (!inviter) {
      throw new Error('邀请人不存在');
    }
    
    // 获取接收者的Socket
    const receiverSocketId = userSockets.get(toUserId);
    
    // 如果接收者在线，发送邀请通知
    if (receiverSocketId) {
      io.to(receiverSocketId).emit('groupInvitation', {
        groupId,
        groupName: groups[0].name,
        groupAvatar: groups[0].group_avatar,
        from: {
          _id: inviter._id,
          username: inviter.username,
          avatar: inviter.avatar
        }
      });
    }
    
    return true;
  } catch (error) {
    console.error('发送群组邀请通知失败:', error);
    return false;
  }
};

// 通知群组加入请求
const notifyGroupJoinRequest = async (groupId, userId, io) => {
  try {
    console.log(`🔔 开始发送群组加入请求通知: 群组 ${groupId}, 用户 ${userId}`);
    
    // 获取用户信息
    const requester = await User.findById(userId).select('username avatar');
    if (!requester) {
      console.log('❌ 请求者不存在:', userId);
      throw new Error('请求者不存在');
    }
    
    console.log(`👤 请求者信息: ${requester.username} (${requester._id})`);
    
    // 获取群组管理员
    const admins = await query(
      `SELECT gm.user_id FROM group_members gm 
       WHERE gm.group_id = ? AND gm.role = 'admin'`,
      [groupId]
    );
    
    console.log(`👑 找到 ${admins.length} 个群组管理员:`, admins.map(a => a.user_id));
    
    let notifiedCount = 0;
    
    // 向所有在线管理员发送通知
    for (const admin of admins) {
      const adminId = admin.user_id;
      const adminSocketId = userSockets.get(adminId);
      
      console.log(`🔍 检查管理员 ${adminId}: ${adminSocketId ? '在线' : '离线'}`);
      
      if (adminSocketId) {
        const notificationData = {
          groupId,
          from: {
            _id: requester._id,
            username: requester.username,
            avatar: requester.avatar
          }
        };
        
        console.log(`📨 向管理员 ${adminId} 发送通知:`, notificationData);
        io.to(adminSocketId).emit('groupJoinRequest', notificationData);
        notifiedCount++;
      }
    }
    
    console.log(`✅ 群组加入请求通知发送完成: ${notifiedCount}/${admins.length} 个管理员收到通知`);
    return true;
  } catch (error) {
    console.error('❌ 发送群组加入请求通知失败:', error);
    return false;
  }
};

// 整个Socket.IO服务设置
const setupSocketIO = (io) => {
  // 使用中间件进行身份验证
  io.use(socketAuth);

  io.on('connection', async (socket) => {
    console.log(`用户已连接: ${socket.user.username}, ID: ${socket.user._id}`);
    
    // 更新用户状态为在线
    const userId = socket.user._id.toString();
    userSockets.set(userId, socket.id);
    
    // 通知该用户的好友其上线状态
    await emitUserStatus(userId, 'online', io, Object.fromEntries(userSockets));

    // 处理私人消息
    socket.on('privateMessage', async (data) => {
      try {
        console.log('收到私人消息:', data);
        const { message, receiverId } = data;
        
        if (!message || !receiverId) {
          console.error('消息格式不正确:', data);
          return;
        }
        
        // 保存并发送消息
        const savedMessage = await saveAndSendMessage(
          socket.user._id.toString(),
          receiverId,
          message.content || message,
          message.type || 'text',
          io
        );
        
        if (savedMessage) {
          console.log('消息已保存并发送:', savedMessage._id);
        }
      } catch (error) {
        console.error('处理私人消息错误:', error);
      }
    });

    // 处理群组消息
    socket.on('groupMessage', async (data) => {
      try {
        console.log('收到群组消息:', data);
        const { message, groupId } = data;
        
        if (!message || !groupId) {
          console.error('群组消息格式不正确:', data);
          return;
        }
        
        // 保存并广播群组消息
        const savedMessage = await saveAndBroadcastGroupMessage(
          socket.user._id.toString(),
          groupId,
          message.content || message,
          message.type || 'text',
          io
        );
        
        if (savedMessage) {
          console.log('群组消息已保存并广播:', savedMessage._id);
        }
      } catch (error) {
        console.error('处理群组消息错误:', error);
      }
    });

    // 处理群组邀请
    socket.on('groupInvitation', async (data) => {
      try {
        const { groupId, userId } = data;
        
        if (!groupId || !userId) {
          console.error('群组邀请格式不正确:', data);
          return;
        }
        
        // 发送群组邀请通知
        await notifyGroupInvitation(groupId, socket.user._id.toString(), userId, io);
      } catch (error) {
        console.error('处理群组邀请错误:', error);
      }
    });

    // 处理群组加入请求
    socket.on('groupJoinRequest', async (data) => {
      try {
        const { groupId } = data;
        
        if (!groupId) {
          console.error('群组加入请求格式不正确:', data);
          return;
        }
        
        // 发送群组加入请求通知
        await notifyGroupJoinRequest(groupId, socket.user._id.toString(), io);
      } catch (error) {
        console.error('处理群组加入请求错误:', error);
      }
    });

    // 处理好友请求通知
    socket.on('friendRequest', async (data) => {
      try {
        const { receiverId } = data;
        
        // 获取接收者的Socket ID
        const receiverSocketId = userSockets.get(receiverId);
        
        // 如果接收者在线，发送通知
        if (receiverSocketId) {
          io.to(receiverSocketId).emit('friendRequest', {
            from: {
              _id: socket.user._id,
              username: socket.user.username,
              avatar: socket.user.avatar
            }
          });
        }
      } catch (error) {
        console.error('发送好友请求通知错误:', error);
      }
    });

    // 处理好友请求回应通知
    socket.on('friendRequestResponse', async (data) => {
      try {
        const { requesterId, status } = data;
        
        // 获取请求者的Socket ID
        const requesterSocketId = userSockets.get(requesterId);
        
        // 如果请求者在线，发送通知
        if (requesterSocketId) {
          io.to(requesterSocketId).emit('friendRequestResponse', {
            from: {
              _id: socket.user._id,
              username: socket.user.username
            },
            status
          });
        }
      } catch (error) {
        console.error('发送好友请求回应通知错误:', error);
      }
    });

    // 处理用户正在输入的状态
    socket.on('typing', (data) => {
      const { receiverId, groupId } = data;
      
      // 处理私人对话的输入状态
      if (receiverId) {
        const receiverSocketId = userSockets.get(receiverId);
        
        if (receiverSocketId) {
          io.to(receiverSocketId).emit('typing', {
            senderId: socket.user._id,
            typing: true,
            isGroup: false
          });
        }
      } 
      // 处理群组对话的输入状态
      else if (groupId) {
        // 广播给群组内的其他成员
        socket.broadcast.to(`group:${groupId}`).emit('typing', {
          senderId: socket.user._id,
          typing: true,
          isGroup: true,
          groupId,
          username: socket.user.username
        });
      }
    });

    // 处理用户停止输入的状态
    socket.on('stopTyping', (data) => {
      const { receiverId, groupId } = data;
      
      // 处理私人对话的停止输入状态
      if (receiverId) {
        const receiverSocketId = userSockets.get(receiverId);
        
        if (receiverSocketId) {
          io.to(receiverSocketId).emit('typing', {
            senderId: socket.user._id,
            typing: false,
            isGroup: false
          });
        }
      } 
      // 处理群组对话的停止输入状态
      else if (groupId) {
        // 广播给群组内的其他成员
        socket.broadcast.to(`group:${groupId}`).emit('typing', {
          senderId: socket.user._id,
          typing: false,
          isGroup: true,
          groupId,
          username: socket.user.username
        });
      }
    });

    // 加入群组房间 - 用于处理群组消息的实时通信
    socket.on('joinGroupRoom', async (data) => {
      try {
        const { groupId } = data;
        
        if (!groupId) {
          return;
        }
        
        // 验证用户是否是群组成员
        const membership = await query(
          'SELECT * FROM group_members WHERE group_id = ? AND user_id = ?',
          [groupId, socket.user._id.toString()]
        );
        
        if (membership.length > 0) {
          // 加入群组房间
          socket.join(`group:${groupId}`);
          console.log(`用户 ${socket.user.username} 加入群组房间: ${groupId}`);
        }
      } catch (error) {
        console.error('加入群组房间错误:', error);
      }
    });

    // 离开群组房间
    socket.on('leaveGroupRoom', (data) => {
      const { groupId } = data;
      
      if (groupId) {
        socket.leave(`group:${groupId}`);
        console.log(`用户 ${socket.user.username} 离开群组房间: ${groupId}`);
      }
    });

    // 处理断开连接
    socket.on('disconnect', async () => {
      console.log(`用户已断开连接: ${socket.user.username}`);
      
      // 从映射中移除
      userSockets.delete(userId);
      
      // 通知该用户的好友其离线状态
      await emitUserStatus(userId, 'offline', io, Object.fromEntries(userSockets));
    });
  });
};

module.exports = {
  setupSocketIO,
  socketAuth,
  emitUserStatus,
  saveAndSendMessage,
  saveAndBroadcastGroupMessage,
  notifyGroupInvitation,
  notifyGroupJoinRequest,
  userSockets
}; 